const Router = require("koa-router")
const { Op, QueryTypes } = require("sequelize")
const ResBody = require("../struct/ResBody")
const bcypt = require("../utils/bcypt")
const { sysConfig } = require("../config")
const db = require("../db")
const { User, Token, Building, Room, UserRoomInRelation } = require("../model")
const {
  UserController,
  RoomController,
  FloorController,
  BuildingController
} = require("../controller")
const utils = require("../utils")

const router = new Router()

router.post("/register", async context => {
  let { account, password } = context.request.body
  if ((await User.findByAccount(account)) !== null) {
    const e = new Error("400-该学号/职工号已被注册")
    throw e
  }
  let user = await User.createUser(account, password)
  context.body = new ResBody({ data: user })
})

router.post("/gotoLogin", async context => {
  let userInfo = context.request.body
  let user = await User.findByAccount(userInfo.account)
  if (null === user) {
    throw new Error("登录失败：用户名错误")
  }
  let verifyFlag = bcypt.verify(userInfo.password, user.password)
  if (verifyFlag) {
    const authToken = await Token.createToken(user.id)
    context.body = new ResBody({ data: { token: authToken } })
  } else {
    context.body = new ResBody({ success: false, msg: "登录失败：密码错误" })
  }
})

router.get("/info", async context => {
  let token = context.req.headers.authorization
  const { tokenId, userId, exp, role } = context.state.user
  // 1. 检查距离Token的过期时间
  const current = parseInt(String(new Date().valueOf() / 1000))
  if (exp - current < sysConfig.tokenExp / 2) {
    // 2. 如果相差超过一半时间，就创建一个新Token并返回
    Token.deleteById(tokenId)
    token = await Token.createToken(userId)
  }
  // 获取用户信息，前端在拿到用户信息后必须重新 set token，保证 token 为最新的
  let user = await User.findOne({ where: { id: userId } })
  if (role === "student" && user.roomId) {
    const room = await user.getRoom()
    const floor = await room.getFloor()
    const building = await floor.getBuilding()
    user = user.toJSON()
    user.room = room
    user.floor = floor
    user.building = building
  }
  if (user !== null) {
    user.token = token
    context.body = new ResBody({ data: user })
  } else {
    let e = new Error("未找到相关用户信息")
    throw e
  }
})

router.post("/updateUserInfo", async context => {
  let stateUserInfo = context.state.user
  const submitInfo = context.request.body
  // 如果请求的参数体中带有userId字段，则可以修改，只有管理员才能修改用户信息
  if (submitInfo.userId) {
    if ("superAdmin" !== stateUserInfo.role) {
      throw new Error("更新失败：您无权限操作")
    }
  }
  await UserController.updateUserInfo(submitInfo).then(res => {
    context.body = new ResBody({ data: res })
  }).catch(error => {
    context.body = new ResBody({ data: null, msg: error.message, success: false })
  })
})

router.post("/clearRoomId", async context => {
  let { userId, role } = context.state.user
  const reqBody = context.request.body
  // 如果请求体中有userId，说明是管理员在修改用户信息
  if (reqBody.userId) {
    if (role !== "superAdmin") {
      throw new Error("403-拒绝访问API")
    }
    userId = reqBody.userId
  }
  const user = await User.findOne({ where: { id: userId } })
  for (let key in reqBody) {
    if (
      Object.hasOwnProperty.call(user.toJSON(), key) &&
      ![undefined, null, ""].includes(reqBody[key])
    ) {
      user[key] = reqBody[key]
    }
  }
  // 将roomid设置为null
  user.roomId = null
  if (reqBody.password) {
    user.password = bcypt.hash(reqBody.password)
  }

  const result = await UserController.updateUserInfo(context.state.user, context.request.body)
  context.body = new ResBody({ data: result })
})

router.get("/getStudents", async context => {
  const { buildingId, floorId, roomId } = context.request.query
  let users = []
  if (roomId) {
    users = await RoomController.getStudents(roomId)
  } else if (floorId) {
    users = await FloorController.getStudents(floorId)
  } else if (buildingId) {
    users = await BuildingController.getStudents(buildingId)
  } else {
    users = await User.findAll({ where: { role: "student" } })
    users = await UserController.getStudentsInfo(users)
  }
  context.body = new ResBody({
    data: { users }
  })
})

router.get("/searchAdmin", async context => {
  const { keywords } = context.request.query
  let admins = []
  if (keywords.trim()) {
    admins = await User.findAll({
      where: {
        role: "admin",
        [Op.or]: {
          name: { [Op.like]: `%${keywords}%` },
          account: { [Op.like]: `%${keywords}%` }
        }
      }
    })
  }
  context.body = new ResBody({ data: { admins, total: admins.length } })
})

router.get("/searchUser", async context => {
  const { keywords } = context.request.query
  let students = []
  if (keywords.trim()) {
    students = await User.findAll({
      where: {
        role: "student",
        [Op.or]: {
          name: { [Op.like]: `%${keywords}%` },
          account: { [Op.like]: `%${keywords}%` }
        }
      }
    })
  }
  context.body = new ResBody({ data: { students, total: students.length } })
})
// 新增用户
router.post("/saveUser", async context => {
  let submitInfo = context.request.body
  utils.checkParams({
    name: submitInfo.name,
    account: submitInfo.account,
    phone: submitInfo.phone,
    password: submitInfo.password,
    role: submitInfo.role,
    facultyId: submitInfo.facultyId,
    majorId: submitInfo.majorId
  })
  if ((await User.findByAccount(submitInfo.account)) !== null) {
    throw new Error("保存失败：该学号/职工号已被注册")
  }
  if ((await User.findByPhone(submitInfo.phone)) !== null) {
    throw new Error("保存失败：该电话已被注册")
  }
  let userInfo = await User.create({
    name: submitInfo.name,
    phone: submitInfo.phone,
    account: submitInfo.account,
    password: bcypt.hash(submitInfo.password),
    role: submitInfo.role,
    facultyId: submitInfo.facultyId,
    majorId: submitInfo.majorId
  })
  context.body = new ResBody({ data: userInfo })
})

router.post("/addAdmin", async context => {
  console.log(context.state)
  const currentUserRole = context.state.user.role
  if (currentUserRole !== "superAdmin") {
    throw new Error("403-拒绝访问API")
  }
  let { name, account, phone, password, role } = context.request.body
  utils.checkParams({ name, account, phone, password, role })
  if ((await User.findByAccount(account)) !== null) {
    const e = new Error("400-该学号/职工号已被注册")
    throw e
  }
  let user = await User.create({
    name,
    phone,
    account,
    password: bcypt.hash(password),
    role
  })
  context.body = new ResBody({ data: user })
})

router.get("/getAdminTableData", async context => {
  const admins = await User.findAll({
    where: {
      role: { [Op.or]: ["admin", "superAdmin"] }
    },
    include: [{ model: Building }]
  })
  context.body = new ResBody({ data: { admins, total: admins.length } })
})

router.get("/getStudentInfoByIdOrAccount", async context => {
  const { type, value } = context.request.query
  let userId = value
  if (type !== "id") {
    const user = await User.findOne({ where: { account: value } })
    if (!user) {
      throw new Error("无法找到该用户")
    }
    userId = user.id
  }
  const userInfo = await UserController.getStudentInfo(userId)
  context.body = new ResBody({ data: userInfo })
})

// 自动分配宿舍
router.get("/autoFenpeiRoom", async context => {

  // 查询所有未被分配的人
  const waitUsers = await User.findAll({
    where: {
      roomId: null,
      role: 'student'
    }
  })
  let users = []
  waitUsers.forEach(user => {
    users.push({
      userId: user.dataValues.id,
      roomId: 0
    })
  })

  if (users.length <= 0) {
    context.body = new ResBody({
      data: null,
      msg: "分配失败：不存在未分配宿舍学生",
      success: false
    })
    return
  }
  // 查询所有未住满的房间
  const notFullRooms = await db.sequelize.query("SELECT * FROM `rooms` WHERE  alreadyNum < peopleNum ", { type: QueryTypes.SELECT });
  if (notFullRooms === null || notFullRooms.length <= 0) {
    context.body = new ResBody({
      data: null,
      msg: "分配失败：宿舍已满员",
      success: false
    })
    return
  }

  let position = 0;
  for (const index in notFullRooms) {
    let room = notFullRooms[index]
    let roomNotFullFlag = true;
    while (roomNotFullFlag) {
      if (room.alreadyNum <= room.peopleNum && position < users.length) {
        let user = users[position]
        user.roomId = room.id
        position++
        room.alreadyNum++
        await UserController.updateUserInfo(user).then(originUser => {
          console.log("保存用户成功--->", originUser.id)
        }).catch(error => {
          console.log("房间分配失败", error.message)
          position--
          room.alreadyNum--
          roomNotFullFlag = false
        })
      } else {
        roomNotFullFlag = false
      }
    }
    if (position >= users.length) {
      break
    }
  }

  context.body = new ResBody({
    data: null,
    msg: position >= users.length ? "宿舍分配已完成" : "房间满员，已完成部分学生宿舍分配"
  })
})

// 智能分配宿舍 （考虑性别、学院、专业）
router.get("/smartFenpeiRoom", async context => {

  // 查询所有未被分配的人
  const waitUsers = await User.findAll({
    where: {
      roomId: null,
      role: 'student'
    }
  })
  let waitCouunt = waitUsers.length
  for (const index in waitUsers) {
    const user = waitUsers[index]
    const notFullRoomIds = []
    const notFullRomms = await Room.findAll({
      where: {
        status: 1,
        sex: user.sex
      }
    })
    const roomScoreMap = new Map();
    notFullRomms.forEach(async room => {
      if (room.alreadyNum < room.peopleNum) {
        notFullRoomIds.push(room.id)
        roomScoreMap.set(room.id, 0)
      }
    })
    const userRoomInRelations = await UserRoomInRelation.findAll({
      where: {
        roomId: { [Op.in]: notFullRoomIds }
      }
    })
    userRoomInRelations.forEach(async relation => {
      let score = 0
      if (user.id === relation.userId) {
        score += 5;
      }
      if (user.sex === relation.sex) {
        score += 3;
      }
      if (user.facultyId === relation.facultyId) {
        score += 1;
      }
      if (user.majorId === relation.majorId) {
        score += 2;
      }

      const existSocre = roomScoreMap.get(relation.roomId)
      if (existSocre != null) {
        score += existSocre;
      }
      roomScoreMap.set(relation.roomId, score)
    })

    const sortMap = new Map([...roomScoreMap].sort((a, b) => b[1] - a[1]));
    if (sortMap.size > 0) {
      const bestRoomId = sortMap.keys().next().value
      UserController.updateUserInfo({
        userId: user.id,
        roomId: bestRoomId
      }).then(originUser => {
        waitCouunt--;
        console.log("保存用户成功--->", originUser.id)
      }).catch(error => {
        context.body = new ResBody({
          data: null,
          msg: error.message,
          success: false
        })
        return
      });
    }
  }

  context.body = new ResBody({
    data: null,
    msg: waitCouunt > 0 ? `部分学生分配完成，剩余${waitCouunt}个学生未分配` : "宿舍分配已完成"
  })
})

// 未分配宿舍学生分页
router.get("/page/noFenpeiInfo", async context => {
  let {
    current,
    step
  } = context.request.query
  current = current ? parseInt(current) : 1
  step = step ? parseInt(step) : 10
  let data = {
    count: 0,
    rows: []
  }
  data = await UserController.getNoFenpeiPageInfo({
    current, step
  })
  context.body = new ResBody({
    data: {
      current, step, count: data.count, rows: data.rows
    }
  })
})

// 已分配宿舍学生分页
router.get("/page/FenpeiedInfo", async context => {
  let { current, step, buildingId, floorId, roomId, keyword } = context.request.query
  current = current ? parseInt(current) : 1
  step = step ? parseInt(step) : 10
  let data = {
    count: 0,
    rows: []
  }
  data = await UserController.getFenpeiedPageInfo({ current, step, buildingId, floorId, roomId, keyword })
  context.body = new ResBody({
    data: {
      current, step, count: data.count, rows: data.rows
    }
  })
})


module.exports = router.routes()
